package com.tarena.lbs.coupon.service.handler.issue;

import com.tarena.lbs.coupon.api.pojo.param.UserCouponsParam;
import com.tarena.lbs.coupon.dao.repository.CouponRepository;
import com.tarena.lbs.coupon.dao.repository.StockRepository;
import com.tarena.lbs.coupon.dao.repository.UserCouponsRepository;
import com.tarena.lbs.coupon.enums.CouponEnableStatus;
import com.tarena.lbs.coupon.enums.CouponStatus;
import com.tarena.lbs.coupon.pojo.po.CouponPO;
import com.tarena.lbs.coupon.pojo.po.CouponStockPO;
import com.tarena.lbs.coupon.pojo.po.UserCouponsPO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;

/**
 * @className: CouponIssueValidator
 * @author: Feng-hongliang
 * @date: 2025/10/11 19:48
 * @Version: 1.0
 * @description: 用户领取优惠券的校验
 */
@Slf4j
@Component
public class CouponIssueValidator {
    final public static String MESSAGE_KEY = "msg";
    static final public String RESULT_KEY = "result";

    private final CouponRepository couponRepository;
    private final StockRepository stockRepository;
    private final UserCouponsRepository userCouponsRepository;

    public CouponIssueValidator(CouponRepository couponRepository,
                                StockRepository stockRepository,
                                UserCouponsRepository userCouponsRepository) {
        this.couponRepository = couponRepository;
        this.stockRepository = stockRepository;
        this.userCouponsRepository = userCouponsRepository;
    }

    /*
     * 检查优惠券是否可用
     * 用户是否可以领取
     * 检查库存是否充足
     */

    /**
     * 统一校验用户领券条件
     *
     * @param param 用户领券参数
     */
    public Map<String, Object> validateUserCanReceiveCoupon(UserCouponsParam param) {
        Map<String, Object> result = new HashMap<>();
        // 参数校验
        Map<String, Object> paramValidationResult = userCouponsParamValid(param);
        if (!(Boolean) paramValidationResult.getOrDefault(RESULT_KEY, false)) {
            paramValidationResult.put(MESSAGE_KEY, "参数验证失败");
            result.put(RESULT_KEY, false);
            return result;
        }

        // 预先查询优惠券信息，避免多次查询数据库
        CouponPO couponPO = couponRepository.findById(param.getCouponId());
        if (couponPO == null) {
            log.trace("优惠券不存在");
            result.put(RESULT_KEY, false);
            result.put(MESSAGE_KEY, "优惠券不存在");
            return result;
        }

        // 优惠券可用性校验
        if (!checkCouponAvailable(couponPO)) {
            log.trace("优惠券不可用");
            result.put(MESSAGE_KEY, "优惠券不可用");
            result.put(RESULT_KEY, false);
            return result;
        }

        // 用户领取资格校验
        if (!checkUserCanReceiveCoupon(couponPO, param.getUserId())) {
            log.trace("用户已领取过该优惠券,或者已达上限，用户已领");
            result.put(MESSAGE_KEY, "用户法无领取");
            result.put(RESULT_KEY, false);
            return result;
        }

        // 库存校验
        if (!checkCouponStock(couponPO)) {
            log.trace("优惠券库存不足");
            result.put(MESSAGE_KEY, "优惠券库存不足");
            result.put(RESULT_KEY, false);
            return result;
        }
        result.put(RESULT_KEY, true);
        result.put(MESSAGE_KEY, "用户可领取");
        return result;
    }

    /**
     * 检查优惠券是否可用状态<br/>
     * 检查是否
     *
     * @param couponPO 优惠券实体
     * @return 可用返回true，否则返回false
     */
    private boolean checkCouponAvailable(CouponPO couponPO) {
//        检查优惠券是否被启用，检查的是enable_status字段
        boolean equals = Objects.equals(CouponEnableStatus.ENABLED.getCode(), couponPO.getEnableStatus());
//        优惠券是否可以被领取，检查的是statue字段
        CouponStatus couponStatus = CouponStatus.fromCode(couponPO.getStatus());
        boolean claimable = couponStatus.isClaimable();
        return equals && claimable;
    }

    /**
     * 检查用户是否可以领取该优惠券
     * <p>
     * 主要判断的是优惠券是否被领取过，被领取过则不能再领取；
     * 用户是否可以领取，有没有领取限制，例如黑名单。
     *
     * @param couponPO 优惠券实体
     * @param userId   用户id
     * @return
     */
    private boolean checkUserCanReceiveCoupon(CouponPO couponPO, Integer userId) {
        // TODO: 实现用户领取资格校验逻辑
        // 示例：暂时返回true，实际应检查用户是否已领取过该优惠券、是否在黑名单中等
        Integer poId = couponPO.getId();
//        根据优惠券id进行查找
        List<UserCouponsPO> userCouponsPO = userCouponsRepository.findByCouponId(poId);
//        获取最大领取数量
        Integer maxUsageLimit = couponPO.getUsageLimit();
        if (userCouponsPO.size() >= maxUsageLimit) {
            log.debug("用户已领取过该优惠券,或者已达上限，用户已领：{}", userCouponsPO.size());
            return false;
        }
        return true;
    }

    /**
     * 检查优惠券库存是否充足
     *
     * @param couponPO 优惠券实体
     * @return 充足返回true，否则返回false
     */
    private boolean checkCouponStock(CouponPO couponPO) {
        // TODO: 实现库存校验逻辑
        // 示例：暂时返回true，实际应检查优惠券库存是否充足
        Integer poId = couponPO.getId();
        CouponStockPO couponStockPO = stockRepository.findByCouponId(poId);
        if (couponStockPO == null) {
            log.warn("优惠券库存不存在，couponId={}", poId);
            return false;
        }
        boolean stock = couponStockPO.getNum() > 0;
        log.trace("优惠券的id为{}，库存充为：{}", poId, couponStockPO.getNum());
        return stock;
    }

    /**
     * 验证用户优惠券参数
     *
     * @param param 用户优惠券参数
     * @return 验证结果，被自带的result数据类搞得有点崩溃，这个方法用map代替。<br/>
     * 如果验证通过返回空Map，否则返回错误信息
     * <p>
     * 返回的是map，它目前定义了两个key，具体数据如下:
     * msg: 详细信息, 一般出现错误才会有这个信息
     * code: 错误码
     * </p>
     */
    private Map<String, Object> userCouponsParamValid(UserCouponsParam param) {
        Map<String, Object> validationResult = new HashMap<>();
        validationResult.put(RESULT_KEY, true);

        if (param == null) {
            validationResult.put(RESULT_KEY, false);
            validationResult.put(MESSAGE_KEY, "参数不能为空");
            return validationResult;
        }

        if (param.getUserId() == null || param.getUserId() <= 0) {
            validationResult.put("result", false);

            validationResult.put("userId", "用户ID不能为空且必须大于0");
            validationResult.put(MESSAGE_KEY, "用户ID不能为空且必须大于0");
        }

        if (param.getCouponId() == null || param.getCouponId() <= 0) {
            validationResult.put("result", false);
            validationResult.put(MESSAGE_KEY, "优惠券ID不能为空且必须大于0");
        }

        if (param.getReceiveChannel() == null) {
            validationResult.put("result", false);
            validationResult.put(MESSAGE_KEY, "领取渠道不能为空");
//            validationResult.put("receiveChannel", "领取渠道不能为空");
        }

        // TODO：activityId不明参数, couponCode 当前逻辑不在判断类，因为有业务生成
        if (param.getShopId() == null) {
            validationResult.put("result", false);
//            validationResult.put(MESSAGE_KEY, "领取渠道不能为空");
            validationResult.put(MESSAGE_KEY, "店铺ID不能为空");
        }
        return validationResult;
    }
}